/**
 * Copyright 2014 the original author or authors. All rights reserved.
 */
package com.visionet.security.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import org.apache.commons.codec.digest.MessageDigestAlgorithms;
import org.apache.commons.lang3.Validate;

import com.visionet.jumper.core.exception.runtime.FrameworkException;

/**
 * 
 *
 * @author suxiaojing
 * @date 
 * @since 0.0.1
 */
public class DigestUtils {
	private static int DEFAULT_ITERATIONS=1;
	private static SecureRandom random = new SecureRandom();

	/**
	 * @param algorithm
	 *            Use {@link MessageDigestAlgorithms}
	 * @return
	 */
	private static MessageDigest getDigest(String algorithm) {
		try {
			return MessageDigest.getInstance(algorithm);
		} catch (NoSuchAlgorithmException e) {
			throw new FrameworkException(e.getMessage(),e);
		}
	}

	/**
	 * Get MD5 digest
	 * 
	 * @return
	 */
	public static MessageDigest getMd5Digest() {
		return getDigest(MessageDigestAlgorithms.MD5);
	}

	/**
	 * 
	 * @param algorithm
	 * @param data
	 * @param salt
	 * @param iterations
	 * @return
	 */
	public static byte[] digest(String algorithm, byte[] data, byte[] salt, int iterations) {
		MessageDigest digest = getDigest(algorithm);
		if (salt != null) {
			digest.reset();
			digest.update(salt);
		}
		byte[] finalBytes = digest.digest(data);
		iterations=iterations-DEFAULT_ITERATIONS;
		for (int i = 0; i < iterations; i++) {
			digest.reset();
			finalBytes = digest.digest(finalBytes);
		}
		return finalBytes;
	}

	/**
	 * @param data
	 * @param salt
	 * @param iterations
	 * @return
	 */
	public static byte[] md5(byte[] data, byte[] salt, int iterations) {
		return digest(MessageDigestAlgorithms.MD5, data, salt, iterations);
	}

	/**
	 * @param data
	 * @param salt
	 * @return
	 */
	public static byte[] md5(byte[] data, byte[] salt) {
		return md5(data, salt, DEFAULT_ITERATIONS);
	}

	/**
	 * @param data
	 * @return
	 */
	public static byte[] md5(byte[] data) {
		return md5(data, null);
	}

	/**
	 * @param data
	 * @return
	 */
	public static String md5Hex(byte[] data) {
		return CodecUtils.encodeHexString(md5(data));
	}

	/**
	 * @param data
	 * @param salt
	 * @return
	 */
	public static String md5Hex(byte[] data, byte[] salt) {
		return CodecUtils.encodeHexString(md5(data,salt));
	}

	/**
	 * @param data
	 * @param salt
	 * @param iterations
	 * @return
	 */
	public static String md5Hex(byte[] data, byte[] salt, int iterations) {
		return CodecUtils.encodeHexString(md5(data, salt, iterations));
	}
	
	/**
	 * @param byteSize
	 * @return
	 */
	public static byte[] generateSalt(int byteSize){
		Validate.isTrue(byteSize>0,"Argument 'byteSize' must be large than [1], for now there is [%d]", byteSize);
		byte[] bytes=new byte[byteSize];
		random.nextBytes(bytes);
		return bytes;
	}
	
	/**
	 * @param byteSize
	 * @return
	 */
	public static String generateSaltHex(int byteSize){
		return CodecUtils.encodeHexString(generateSalt(byteSize));
	}

}
